/*
 * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <inttypes.h>
#include "nvs.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "console_uart.h"

#include "time.h"
#include "sys/time.h"

#include "driver/uart.h"
#include "driver/gpio.h"

#include "at_commond.h"

#define SPP_TAG "SPP_INITIATOR_DEMO"
#define EXAMPLE_DEVICE_NAME "Bluetooth Device"

// #define SPP_SHOW_DATA 0
// #define SPP_SHOW_SPEED 1
// #define SPP_SHOW_MODE SPP_SHOW_SPEED    /*Choose show mode: show data or speed*/

static uint32_t spp_handle;

static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
static const bool esp_spp_enable_l2cap_ertm = true;

static struct timeval  time_old;
//static long data_num = 0;
//SPP配对认证模式与设备角色
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
static const esp_spp_role_t role_master = ESP_SPP_ROLE_MASTER;
//配对设备信息
esp_bd_addr_t peer_bd_addr = {0};
static uint8_t peer_bdname_len;
static char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
//static const char remote_device_name[] = CONFIG_EXAMPLE_PEER_DEVICE_NAME;

static const esp_bt_inq_mode_t inq_mode = ESP_BT_INQ_MODE_GENERAL_INQUIRY;
static const uint8_t inq_len = 8;
static const uint8_t inq_num_rsps = 0;

// #if (SPP_SHOW_MODE == SPP_SHOW_DATA)
// #define SPP_DATA_LEN 20
// #else
// #define SPP_DATA_LEN ESP_SPP_MAX_MTU
// #endif

#define SPP_DATA_LEN ESP_SPP_MAX_MTU
//此处不用static，static修饰全局变量时只对这个文件可见(避免起名冲突)
uint8_t uart_rx_data[SPP_DATA_LEN];
static uint8_t *s_p_data = NULL; /* data pointer of uart_rx_data */

#define ECHO_UART_PORT_NUM UART_NUM_1// 使用 UART1
#define ECHO_UART_BAUD_RATE 1000000    // 波特率设置为 1000000
#define ECHO_TASK_STACK_SIZE 2048     // 任务栈大小
#define BUF_SIZE 2048                 // 接收缓冲区大小

#define NUMBER_CMD_REQ  11// 支持的AT命令个数

void Write_BondiInfo_To_NVS(void);
void BT_connect_state_task(void *arg);
void Write_CheckNums_To_NVS(uint32_t CheckNums);

static QueueHandle_t uart1_queue;
SemaphoreHandle_t  xSPPcongSemaphore;
SemaphoreHandle_t  xBTSearchEndSemaphore;

uint8_t connect_flag;//蓝牙连接标志
uint8_t AT_mode;//AT模式
typedef struct{ //已绑定蓝牙信息结构体
    esp_bd_addr_t  bt_mc_addr;
    char    bt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
    esp_bt_pin_code_t bt_pincode;
} bt_info_bond_t;

bt_info_bond_t BT_bond; //已绑定蓝牙信息

typedef struct{ //搜索到的蓝牙设备信息
    esp_bd_addr_t  bt_mc_addr;
    char    bt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
} bt_info_search_t;

bt_info_search_t bt_info_search[5];//存储搜索到的蓝牙设备信息最多5个
uint8_t number_search = 0;//搜索到的符合要求的蓝牙设备数
uint8_t flag_PC_search = 0;//PC机请求搜索蓝牙标志
TaskHandle_t xHandle;
uint32_t CheckNums_Code = 0; //CH32V208校验码

const char Default_BT_Bond_Name[] = "SOMNO eco 0853";
const char Default_BT_Bond_Pincode[] = "125026";
const uint8_t Default_BT_Bond_addr[] = {0x00, 0x12, 0xf3, 0x3e, 0x3b, 0xa1};

void qyq_uart_init(void)
{
    // 1. 配置串口参数
    uart_config_t uart_config = {
        .baud_rate = ECHO_UART_BAUD_RATE,     // 设置波特率
        .data_bits = UART_DATA_8_BITS,        // 设置数据位为 8 位
        .parity = UART_PARITY_DISABLE,        // 不使用校验位
        .stop_bits = UART_STOP_BITS_1,        // 使用一个停止位
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE // 禁用硬件流控
    };

    // 2. 应用串口配置
    uart_param_config(UART_NUM_1, &uart_config);

    // 3. 设置 TX、RX 引脚（此处使用 GPIO22 为 TX，GPIO23 为 RX）
    uart_set_pin(UART_NUM_1, 22, 23, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    // 4. 安装串口驱动,注册了串口消息队列
    uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 20, &uart1_queue, 0);
}

static char *bda2str(uint8_t * bda, char *str, size_t size)
{
    if (bda == NULL || str == NULL || size < 18) {
        return NULL;
    }

    uint8_t *p = bda;
    sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
            p[0], p[1], p[2], p[3], p[4], p[5]);
    return str;
}
//打印速度函数
// static void print_speed(void)
// {
//     float time_old_s = time_old.tv_sec + time_old.tv_usec / 1000000.0;
//     float time_new_s = time_new.tv_sec + time_new.tv_usec / 1000000.0;
//     float time_interval = time_new_s - time_old_s;
//     float speed = data_num * 8 / time_interval / 1000.0;
//     ESP_LOGI(SPP_TAG, "speed(%fs ~ %fs): %f kbit/s" , time_old_s, time_new_s, speed);
//     data_num = 0;
//     time_old.tv_sec = time_new.tv_sec;
//     time_old.tv_usec = time_new.tv_usec;
// }
//从蓝牙设备的扩展查询响应(EIR)数据中提取设备名称。EIR数据是蓝牙设备在广播时发送的附加信息，包含了设备的各种属性，如设备名、服务UUID等
static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
{
    uint8_t *rmt_bdname = NULL;
    uint8_t rmt_bdname_len = 0;

    if (!eir) {
        return false;
    }

    rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
    if (!rmt_bdname) {
        rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
    }

    if (rmt_bdname) {
        if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
            rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
        }

        if (bdname) {
            memcpy(bdname, rmt_bdname, rmt_bdname_len);
            bdname[rmt_bdname_len] = '\0';
        }
        if (bdname_len) {
            *bdname_len = rmt_bdname_len;
        }
        return true;
    }

    return false;
}
//SPP事件回调函数
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
    uint8_t i = 0;
    char bda_str[18] = {0};

    switch (event) {
    case ESP_SPP_INIT_EVT:
        if (param->init.status == ESP_SPP_SUCCESS) {
            ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
            esp_bt_gap_set_device_name(EXAMPLE_DEVICE_NAME);
            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
            esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);
        } else {
            ESP_LOGE(SPP_TAG, "ESP_SPP_INIT_EVT status:%d", param->init.status);
        }
        break;
    case ESP_SPP_DISCOVERY_COMP_EVT:
        if (param->disc_comp.status == ESP_SPP_SUCCESS) {
            ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT scn_num:%d", param->disc_comp.scn_num);
            for (i = 0; i < param->disc_comp.scn_num; i++) {
                ESP_LOGI(SPP_TAG, "-- [%d] scn:%d service_name:%s", i, param->disc_comp.scn[i],
                         param->disc_comp.service_name[i]);
            }
            /* We only connect to the first found server on the remote SPP acceptor here */
            esp_spp_connect(sec_mask, role_master, param->disc_comp.scn[0], peer_bd_addr);
        } else {
            ESP_LOGE(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT status=%d", param->disc_comp.status);
        }
        break;
    case ESP_SPP_OPEN_EVT:
        if (param->open.status == ESP_SPP_SUCCESS) {
            ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT handle:%"PRIu32" rem_bda:[%s]", param->open.handle,
                     bda2str(param->open.rem_bda, bda_str, sizeof(bda_str)));
            /* Start to write the first data packet */
            //将handle存储起来
            spp_handle=param->open.handle;
           // esp_spp_write(param->open.handle, SPP_DATA_LEN, uart_rx_data);
            s_p_data = uart_rx_data;
            gettimeofday(&time_old, NULL);
        } else {
            ESP_LOGE(SPP_TAG, "ESP_SPP_OPEN_EVT status:%d", param->open.status);
        }
        gpio_set_level(GPIO_NUM_26, 0);
        connect_flag = 1;
        break;
    case ESP_SPP_CLOSE_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT status:%d handle:%"PRIu32" close_by_remote:%d", param->close.status,
                 param->close.handle, param->close.async);
        gpio_set_level(GPIO_NUM_26, 1);
        connect_flag = 0;
        break;
    case ESP_SPP_START_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
        break;
    case ESP_SPP_CL_INIT_EVT:
        if (param->cl_init.status == ESP_SPP_SUCCESS) {
            ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT handle:%"PRIu32" sec_id:%d", param->cl_init.handle, param->cl_init.sec_id);
        } else {
            ESP_LOGE(SPP_TAG, "ESP_SPP_CL_INIT_EVT status:%d", param->cl_init.status);
        }
        break;
    case ESP_SPP_DATA_IND_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT");
        ESP_LOGI(SPP_TAG, "data_ind.len is %d",param->data_ind.len);
        uart_write_bytes(UART_NUM_1, param->data_ind.data, param->data_ind.len); 
        break;
//发生时机
//数据发送完成:当通过SPP协议成功发送数据后，ESP_SPP_WRITE_EVT事件通常会被触发。
//这表示数据已经从发送缓冲区被成功发送出去，并日接收端可能已经接收到这些数据(但这一点取决于通信的可嘉性和接收端的处理速度。
//作用与意义(确认数据发送:ESP_SPP_WRITE_EVT事件的主要作用是确认数据已经成功发送。这对于确保通信的可靠性和完整性至关重要。
//触发后续操作:在某些情况下;当数据发送完成后，可能需要执行一些后续操作，如更新发送状态、发送下一条数据或关闭连接等。ESP SPP WRITE EVT事件可以作为一个触发点，用于执行这些后续操作。
    case ESP_SPP_WRITE_EVT:
        if (param->write.status == ESP_SPP_SUCCESS) {

          if (param->write.cong == 0) { //阻塞标志为0，释放阻塞信息量
           xSemaphoreGive(xSPPcongSemaphore);
        }
           ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT %ddata send success", param->write.len);
        } else {
            /* Means the previous data packet is not sent at all, need to send the whole data packet again. */
            ESP_LOGE(SPP_TAG, "ESP_SPP_WRITE_EVT status:%d", param->write.status);
        }
        /*
         * If you don't want to manage this complicated process, we also provide the SPP VFS mode that hides the
         * implementation details. However, it is less efficient and will block the caller until all data has been sent.
         */
        break;
    case ESP_SPP_CONG_EVT://SPP阻塞状态改变事件
         ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT cong:%d", param->cong.cong);
        if (param->cong.cong == 0) {
            /* Send the privous (partial) data packet or the next data packet. */
           xSemaphoreGive(xSPPcongSemaphore);
        }
        break;
    case ESP_SPP_SRV_OPEN_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
        break;
    case ESP_SPP_UNINIT_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_UNINIT_EVT");
        break;
    default:
        break;
    }
}
//GAP事件回调函数
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
    switch(event){
    case ESP_BT_GAP_DISC_RES_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_RES_EVT");
        if(flag_PC_search){  //PC机请求搜索蓝牙
            ESP_LOG_BUFFER_HEX(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
            /* Find the target peer device name in the EIR data */
            for (int i = 0; i < param->disc_res.num_prop; i++){
                if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
                    && get_name_from_eir(param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){//获取搜索到的设备名及长度
                    ESP_LOG_BUFFER_CHAR(SPP_TAG, peer_bdname, peer_bdname_len);
                    if (strncmp(peer_bdname, "SOMNO", 5) == 0 || strncmp(peer_bdname, "SOT", 3) == 0) {
                        //  printf("number_search:%d\n",number_search);
                        if(number_search == 0)
                        {
                            memcpy(bt_info_search[number_search].bt_mc_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
                            memcpy(bt_info_search[number_search].bt_name, peer_bdname, peer_bdname_len);
                            number_search++;
                        }else{
                            for(uint8_t j = number_search; j == 0; j--) //循环历遍查询是否与已存储的设备重名
                            {
                                if(strncmp(peer_bdname, bt_info_search[j-1].bt_name, peer_bdname_len) != 0)
                                {
                                    memcpy(bt_info_search[number_search].bt_mc_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
                                    memcpy(bt_info_search[number_search].bt_name, peer_bdname, peer_bdname_len);
                                    number_search++;
                                }else{
                                    break;
                                }
                            }          
                        }
                                                          
                        if(number_search == 5){//搜索到5个满足要求设备后，主动结束搜索
                            esp_bt_gap_cancel_discovery();
                            xSemaphoreGive(xBTSearchEndSemaphore);//给出结束搜索信号量
                        }
                    }
                }
            }

        }else{              //设备自动连接绑定蓝牙
            ESP_LOG_BUFFER_HEX(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
            /* Find the target peer device name in the EIR data */
            for (int i = 0; i < param->disc_res.num_prop; i++){
                if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
                    && get_name_from_eir(param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){//获取搜索到的设备名及长度
                    ESP_LOG_BUFFER_CHAR(SPP_TAG, peer_bdname, peer_bdname_len);
                    if (strlen(BT_bond.bt_name) == peer_bdname_len
                        && strncmp(peer_bdname, BT_bond.bt_name, peer_bdname_len) == 0) {
                        memcpy(peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
                        memcpy(BT_bond.bt_mc_addr, peer_bd_addr, ESP_BD_ADDR_LEN);
                        /* Have found the target peer device, cancel the previous GAP discover procedure. And go on
                        * dsicovering the SPP service on the peer device */
                        esp_bt_gap_cancel_discovery();
                        if(memcmp(peer_bd_addr, BT_bond.bt_mc_addr, ESP_BD_ADDR_LEN) != 0){ 
                            Write_BondiInfo_To_NVS();
                        };
                        esp_spp_start_discovery(peer_bd_addr);
                    }
                }
            }
        }
       
        break;
    case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
        break;
    case ESP_BT_GAP_RMT_SRVCS_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_RMT_SRVCS_EVT");
        break;
    case ESP_BT_GAP_RMT_SRVC_REC_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_RMT_SRVC_REC_EVT");
        break;
    case ESP_BT_GAP_AUTH_CMPL_EVT:{
        if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
            ESP_LOGI(SPP_TAG, "authentication success: %s", param->auth_cmpl.device_name);
            ESP_LOG_BUFFER_HEX(SPP_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
        } else {
            ESP_LOGE(SPP_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
        }
        break;
    }
    case ESP_BT_GAP_PIN_REQ_EVT:{
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
        if (param->pin_req.min_16_digit) {
            ESP_LOGI(SPP_TAG, "Input pin code: 0000 0000 0000 0000");
            esp_bt_pin_code_t pin_code = {0};
            esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
        } else {
            ESP_LOGI(SPP_TAG, "Input pin code: %s", BT_bond.bt_pincode);
            
            esp_bt_gap_pin_reply(param->pin_req.bda, true, strlen((char*)BT_bond.bt_pincode), BT_bond.bt_pincode);
        }
        break;
    }

#if (CONFIG_EXAMPLE_SSP_ENABLED == true)
    case ESP_BT_GAP_CFM_REQ_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %06"PRIu32, param->cfm_req.num_val);
        ESP_LOGW(SPP_TAG, "To confirm the value, type `spp ok;`");
        break;
    case ESP_BT_GAP_KEY_NOTIF_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%06"PRIu32, param->key_notif.passkey);
        ESP_LOGW(SPP_TAG, "Waiting response...");
        break;
    case ESP_BT_GAP_KEY_REQ_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
        ESP_LOGW(SPP_TAG, "To input the key, type `spp key xxxxxx;`");
        break;
#endif

    case ESP_BT_GAP_MODE_CHG_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode:%d", param->mode_chg.mode);
        break;

    default:
        break;
    }
}
void classicBT_Init(void)
{
    esp_err_t ret = ESP_OK;
    char bda_str[18] = {0};

    for (int i = 0; i < SPP_DATA_LEN; ++i) {
        uart_rx_data[i] = i;
    }

    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK( ret );
    //释放蓝牙资源
    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
    //初始化蓝牙控制器
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    //启用蓝牙控制器
    if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    //初始化蓝牙协议栈
    esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
#if (CONFIG_EXAMPLE_SSP_ENABLED == false)
    bluedroid_cfg.ssp_en = false;
#endif
    if ((ret = esp_bluedroid_init_with_cfg(&bluedroid_cfg)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
   //启用蓝牙协议栈
    if ((ret = esp_bluedroid_enable()) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s enable bluedroid failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    //注册蓝牙GAP事件回调函数
    if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s gap register failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

#if (CONFIG_EXAMPLE_SSP_ENABLED == true)
    /* Set default parameters for Secure Simple Pairing */
    esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
    esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IN;
    esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
    if (iocap == ESP_BT_IO_CAP_IN || iocap == ESP_BT_IO_CAP_IO) {
        console_uart_init();
        vTaskDelay(pdMS_TO_TICKS(500));
    }
#endif
   //注册蓝牙SPP事件回调函数
    if ((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s spp register failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    //蓝牙功率设置为最大+9dBm
    esp_bredr_tx_power_set(ESP_PWR_LVL_P6, ESP_PWR_LVL_P9);
   //初始化蓝牙SPP协议栈
    esp_spp_cfg_t bt_spp_cfg = {
        .mode = esp_spp_mode,
        .enable_l2cap_ertm = esp_spp_enable_l2cap_ertm,
        .tx_buffer_size = 0, /* Only used for ESP_SPP_MODE_VFS mode */
    };
    //启用蓝牙SPP协议栈
    if ((ret = esp_spp_enhanced_init(&bt_spp_cfg)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s spp init failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    /*
     * Set default parameters for Legacy Pairing
     * Use variable pin, input pin code when pairing
     */
    // esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
    // esp_bt_pin_code_t pin_code;
    // esp_bt_gap_set_pin(pin_type, 0, pin_code);

    ESP_LOGI(SPP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
}

//AT命令解析函数
void AT_CMD_Handle(void)
{
    uint8_t i;
    char TxBuff[300];
    char* cmd_start_addr;//缓存中命令开始地址
    char* cmd_end_addr;//缓存中命令结束地址
    uint8_t cmd_len;//命令长度
    uint32_t CheckNums;//校验码

    memset(TxBuff, 0, sizeof(TxBuff));
    for( i = 0; i < NUMBER_CMD_REQ; i++){
        cmd_start_addr = strstr((char*)uart_rx_data, ATCMD_REQ[i]);
        cmd_end_addr = strstr((char*)uart_rx_data, "\r");
        cmd_len = cmd_end_addr - cmd_start_addr;
        printf("CMD%d len:%d\r\n", i,cmd_len );
        if (strstr((char*)uart_rx_data, ATCMD_REQ[i]) != NULL) break; 
    }

    switch (i)
    {
    case CMD_AT:  // AT命令测试
        /* code */
        //uart_write_bytes(UART_NUM_1, (char*)uart_rx_data, strlen(ATCMD_REQ[CMD_AT]));
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len+1);
        uart_write_bytes(UART_NUM_1, ATCMD_RESP[0], strlen(ATCMD_RESP[0]));
        printf("AT命令: %s\n", ATCMD_REQ[CMD_AT]);
        break;

    case CMD_ADRDRP: //查询默认连接设备
        /* code */
        //uart_write_bytes(UART_NUM_1, (char*)uart_rx_data, strlen(ATCMD_REQ[CMD_ADRDRP])+3);
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        sprintf(TxBuff, "%s*ADRDRP:%x%x%x%x%x%x,34,0,\"%s\"%s", ATCMD_RESP[1], BT_bond.bt_mc_addr[0],BT_bond.bt_mc_addr[1],
            BT_bond.bt_mc_addr[2],BT_bond.bt_mc_addr[3],BT_bond.bt_mc_addr[4],BT_bond.bt_mc_addr[5],BT_bond.bt_name, ATCMD_RESP[0]); 
        uart_write_bytes(UART_NUM_1, TxBuff, strlen(TxBuff));
        printf("AT命令: %s\n", ATCMD_REQ[CMD_ADRDRP]);
        break;

    case CMD_AGLN: //查询本地设备名
        /* code */
        //uart_write_bytes(UART_NUM_1, (char*)uart_rx_data, strlen(ATCMD_REQ[CMD_AGLN])+1);
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        sprintf(TxBuff, "%s%s%s", ATCMD_RESP[1], "*AGLN:\"Bluetooth Device\"", ATCMD_RESP[0]);
        uart_write_bytes(UART_NUM_1, TxBuff, strlen(TxBuff));
        printf("AT命令: %s\n", ATCMD_REQ[CMD_AGLN]);
        break;

    case CMD_AGDD: //搜索设备
        /* code */
        //uart_write_bytes(UART_NUM_1, (char*)uart_rx_data, strlen(ATCMD_REQ[CMD_AGDD])+6);
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);

        esp_bt_gap_cancel_discovery();//停止搜索
        connect_flag = 1;//暂停重连监测
        number_search = 0;//清空搜索到的设备数
        flag_PC_search = 1;
        esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);

        xSemaphoreTake(xBTSearchEndSemaphore, 11000/portTICK_PERIOD_MS);//等待蓝牙搜索结束最长22秒
        if(number_search){
            sprintf(TxBuff, "%s*AGDD:%d%s", ATCMD_RESP[1], number_search, ATCMD_RESP[0]);
            uart_write_bytes(UART_NUM_1, TxBuff, strlen(TxBuff));
            for(uint8_t i = 0; i < number_search; i++)
            {
                    memset(TxBuff, 0, sizeof(TxBuff));        
                    sprintf(TxBuff, "*AGDDE:%x%x%x%x%x%x,0,1,\"%s\"%s", bt_info_search[i].bt_mc_addr[0], bt_info_search[i].bt_mc_addr[1],
                        bt_info_search[i].bt_mc_addr[2],bt_info_search[i].bt_mc_addr[3],bt_info_search[i].bt_mc_addr[4],bt_info_search[i].bt_mc_addr[5],
                        bt_info_search[i].bt_name, ATCMD_RESP[1]);
                    uart_write_bytes(UART_NUM_1, TxBuff, strlen(TxBuff));   
            }
        }else{
            sprintf(TxBuff, "%s*AGDD:%d%s", ATCMD_RESP[1], 0, ATCMD_RESP[0]);
            uart_write_bytes(UART_NUM_1, TxBuff, strlen(TxBuff));
        }           
       
        flag_PC_search = 0;
        connect_flag = 0;//重新开启重联监测
        printf("AT命令: %s\n", ATCMD_REQ[CMD_AGDD]);
        break;

    case CMD_ADDM://退出AT命令模式，进入数据传输模式
        /* code */
       // uart_write_bytes(UART_NUM_1, (char*)uart_rx_data, strlen(ATCMD_REQ[CMD_ADDM])+1);
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        uart_write_bytes(UART_NUM_1, ATCMD_RESP[0], strlen(ATCMD_RESP[0]));
        printf("AT命令: %s\n", ATCMD_REQ[CMD_ADDM]);
        printf("退出AT命令模式\r\n");
        AT_mode = 0;//退出AT模式
        vTaskResume(xHandle);//恢复蓝牙重连监测任务
        break;

    case CMD_ADNRP://设置绑定蓝牙数量及断电记忆
        /* code */
       // uart_write_bytes(UART_NUM_1, (char*)uart_rx_data, strlen(ATCMD_REQ[CMD_ADNRP])+5);
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        uart_write_bytes(UART_NUM_1, ATCMD_RESP[0], strlen(ATCMD_RESP[0]));
        printf("AT命令: %s\n", ATCMD_REQ[CMD_ADNRP]);
        break;

    case CMD_ADWDRP://需要绑定的蓝牙设备名称及设置
        /* code */
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        uart_write_bytes(UART_NUM_1, ATCMD_RESP[0], strlen(ATCMD_RESP[0]));
        memset(BT_bond.bt_name, 0, ESP_BT_GAP_MAX_BDNAME_LEN + 1);
        memcpy(BT_bond.bt_name, cmd_start_addr+31, cmd_len-34);

        printf("AT命令: %s\n", ATCMD_REQ[CMD_ADWDRP]);
        break;

    case CMD_AGFP://需要绑定的蓝牙设备的PIN码
        /* code */
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        uart_write_bytes(UART_NUM_1, ATCMD_RESP[0], strlen(ATCMD_RESP[0]));
        memset(BT_bond.bt_pincode, 0, ESP_BT_PIN_CODE_LEN);
        memcpy(BT_bond.bt_pincode, cmd_start_addr+9, 6);
        
        printf("AT命令: %s\n", ATCMD_REQ[CMD_AGFP]);
        break;

    case CMD_AGSM://设置安全模式 AT*AGSM=2,1 2代表强安全模式 1代表断电记忆
        /* code */
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        uart_write_bytes(UART_NUM_1, ATCMD_RESP[0], strlen(ATCMD_RESP[0]));
        printf("AT命令: %s\n", ATCMD_REQ[CMD_AGSM]);
        break;

    case CMD_AMWS://看门狗设置 AT*AMWS=0,0,0,0,1,0 重启模块
        /* code */
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        uart_write_bytes(UART_NUM_1, ATCMD_RESP[0], strlen(ATCMD_RESP[0]));
        printf("AT命令: %s\n", ATCMD_REQ[CMD_AMWS]);
        vTaskDelay(1000/portTICK_PERIOD_MS);
        Write_BondiInfo_To_NVS();
       // esp_restart(); //重启系统
        printf("退出AT命令模式\r\n");
        AT_mode = 0;//退出AT模式
        vTaskResume(xHandle);//恢复蓝牙重连监测任务
        break;
    
    case CMD_AWCN://写入/读取CH32V208的CheckNums AT*AWCN=0,xxxxxxxx 读取  AT*AWCN=1,xxxxxxxx 写入
        /* code */
        printf("num:%x\n", *(cmd_start_addr+8));
        if(*(cmd_start_addr+8) == '1'){ //写入CheckNums
            CheckNums = (*(cmd_start_addr+10)<<24) + (*(cmd_start_addr+11)<<16) + (*(cmd_start_addr+12)<<8) +*(cmd_start_addr+13);
            Write_CheckNums_To_NVS(CheckNums);
        }else{                       //读取CheckNums
           memcpy(cmd_start_addr+10, &CheckNums_Code, 4);
        }
        uart_write_bytes(UART_NUM_1, cmd_start_addr, cmd_len);
        uart_write_bytes(UART_NUM_1, ATCMD_RESP[0], strlen(ATCMD_RESP[0]));
        printf("AT命令: %s\n", ATCMD_REQ[CMD_AWCN]);                 
        break;
    
    default:
        printf("无效命令\r\n");
        break;
    }
}

//串口接收处理任务
void qyq_uart_receive_task(void *arg)
{
    uart_event_t event;                     
         
    while (1)
    {
        //这里用于接收串口的消息队列
        if (xQueueReceive(uart1_queue, (void *)&event, (TickType_t)portMAX_DELAY))
        {
            switch (event.type)
            {
            // 数据可读写的状态
            case UART_DATA:
                // 有数据可读
                int len = uart_read_bytes(UART_NUM_1, uart_rx_data, event.size, portMAX_DELAY);
                if(AT_mode){ 
                    AT_CMD_Handle(); //AT命令处理 
                }else{
                    //判断是否为进入AT模式字符"///""
                    if (strstr((char*)uart_rx_data, "///") != NULL)
                    {
                        printf("进入AT命令模式\r\n");
                        AT_mode = 1;//进入AT模式
                        esp_bt_gap_cancel_discovery();//停止搜索蓝牙
                        xHandle = xTaskGetHandle("Task1"); // 获取任务句柄
                        vTaskSuspend(xHandle);//暂停蓝牙重连监测任务
                        break;
                    }
    
                    // SPP发送数据
                    if (len > 0)
                    {
                        if (pdTRUE == xSemaphoreTake(xSPPcongSemaphore, 500/portTICK_PERIOD_MS)){//等待非阻塞状态
                            ESP_LOGI(SPP_TAG,"uart rx data len is %d", len);
                            esp_spp_write(spp_handle, len, uart_rx_data);
                        }
                    }         
                }
                       
                break;
            case UART_FIFO_OVF:
                // 硬件数据溢出
                uart_flush_input(UART_NUM_1);
                xQueueReset(uart1_queue);
                break;
            case UART_BUFFER_FULL:
                // 环形缓冲区已满
                uart_flush_input(UART_NUM_1);
                xQueueReset(uart1_queue);
                break;
            case UART_BREAK:

                break;
            case UART_PARITY_ERR:

                break;
            case UART_FRAME_ERR:

                break;
            case UART_PATTERN_DET:

                break;
            default:

                break;
            }
        }
    }
}

void uart_data_task_create(void)
{
    xTaskCreate(qyq_uart_receive_task, "qyq_uart_receive_task", 4096, NULL, 10, NULL);
}

void gpio_init(void)
{
    gpio_config_t io_conf = {};
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT_OD;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = 1ULL<<GPIO_NUM_26;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);
    gpio_set_level(GPIO_NUM_26, 1);
}

//蓝牙连接重连监测任务
void BT_connect_state_task(void *arg)
{
    while(1)
    {
        vTaskDelay(5000/portTICK_PERIOD_MS);
        if(connect_flag == 0)
        {
            esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);
            vTaskDelay(10000/portTICK_PERIOD_MS);
        } 
    }
}
//NVS 初始化
void storage_init(void){
    size_t required_size = sizeof(bt_info_bond_t);
    uint8_t flag_Restore = 0;
    memset(BT_bond.bt_name, 0x00 ,strlen( BT_bond.bt_name));
    memset(BT_bond.bt_pincode,0x00,sizeof(BT_bond.bt_pincode));
    memset(BT_bond.bt_mc_addr, 0x00, 6);
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK( err );

    // Open
    printf("\n");
    printf("Opening Non-Volatile Storage (NVS) handle... ");
    nvs_handle_t my_handle;
    err = nvs_open("storage", NVS_READWRITE, &my_handle);
    if (err != ESP_OK) {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    } else {
        printf("Done\n");

        // // Read
        printf("Reading BT bond info from NVS ... ");
        
        err = nvs_get_blob(my_handle, "bt_bond_info", &BT_bond, &required_size);//读取flash中存储的BT绑定信息
        switch (err) {
            case ESP_OK:
                if(BT_bond.bt_name[0] == 0 || BT_bond.bt_pincode[0] == 0) flag_Restore = 1;//重新初始化
                printf("Done\n");
                break;
            case ESP_ERR_NVS_NOT_FOUND:
                flag_Restore = 1;//重新初始化
                printf("The value is not initialized yet!\n");				               
                break;
            default :
                printf("Error (%s) reading!\n", esp_err_to_name(err));
        }
        if(flag_Restore)
        {
            memcpy(BT_bond.bt_name, Default_BT_Bond_Name, strlen(Default_BT_Bond_Name));
            memcpy(BT_bond.bt_pincode, Default_BT_Bond_Pincode, strlen(Default_BT_Bond_Pincode));
            memcpy(BT_bond.bt_mc_addr, Default_BT_Bond_addr, sizeof(Default_BT_Bond_addr));
            err = nvs_set_blob(my_handle, "bt_bond_info", &BT_bond, sizeof(bt_info_bond_t));
            flag_Restore = 0;
            printf("Updating bt bond info to  in NVS ... ");
            printf((err != ESP_OK) ? "Failed!\n" : "Done\n");

            printf("Committing updates in NVS ... ");
            err = nvs_commit(my_handle);
            printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
        }
        printf("BTname:%s BTMC: %x:%x:%x:%x:%x:%x Pincode: %s\n", BT_bond.bt_name, BT_bond.bt_mc_addr[0], 
                    BT_bond.bt_mc_addr[1], BT_bond.bt_mc_addr[2], BT_bond.bt_mc_addr[3],  BT_bond.bt_mc_addr[4],
                    BT_bond.bt_mc_addr[5],BT_bond.bt_pincode);

       printf("Reading CheckNums from NVS ... ");
        
        err = nvs_get_u32(my_handle, "CheckNums", &CheckNums_Code);//读取flash中存储的BT绑定信息
        switch (err) {
            case ESP_OK:
                printf("Done\n");
                printf("CheckNums:%x%x%x%x\n",(uint8_t)(CheckNums_Code>>24),(uint8_t)(CheckNums_Code>>16),
                                    (uint8_t)(CheckNums_Code>>8),(uint8_t)(CheckNums_Code));
                break;
            case ESP_ERR_NVS_NOT_FOUND:
                printf("The value is not initialized yet!\n");
                err = nvs_set_u32(my_handle, "CheckNums", CheckNums_Code);
                printf("Updating CheckNums  in NVS ... ");
                printf((err != ESP_OK) ? "Failed!\n" : "Done\n");

                printf("Committing updates in NVS ... ");
                err = nvs_commit(my_handle);
                printf((err != ESP_OK) ? "Failed!\n" : "Done\n");				               
                break;
            default :
                printf("Error (%s) reading!\n", esp_err_to_name(err));
        }

        // Close
        nvs_close(my_handle);
    }
}

//存储绑定信息
void Write_BondiInfo_To_NVS(void)
{
    printf("\n");
    printf("Opening Non-Volatile Storage (NVS) handle... ");
    nvs_handle_t my_handle;
    esp_err_t err = nvs_open("storage", NVS_READWRITE, &my_handle);
    if (err != ESP_OK) {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    } else {
        printf("Done\n");

        err = nvs_set_blob(my_handle, "bt_bond_info", &BT_bond, sizeof(bt_info_bond_t));
        printf((err != ESP_OK) ? "Failed!\n" : "Done\n");

        printf("Committing updates in NVS ... ");
        err = nvs_commit(my_handle);
        printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
        // Close
        nvs_close(my_handle);
    }
}
//存储校验码
void Write_CheckNums_To_NVS(uint32_t CheckNums)
{
    printf("\n");
    printf("Opening Non-Volatile Storage (NVS) handle... ");
    nvs_handle_t my_handle;
    esp_err_t err = nvs_open("storage", NVS_READWRITE, &my_handle);
    if (err != ESP_OK) {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    } else {
        printf("Done\n");
        err = nvs_set_u32(my_handle, "CheckNums", CheckNums);
        printf((err != ESP_OK) ? "Failed!\n" : "Done\n");

        printf("Committing updates in NVS ... ");
        err = nvs_commit(my_handle);
        printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
        // Close
        nvs_close(my_handle);
    }
}

void app_main(void)
{
    uint8_t RxBuff[4]={0};
    uint32_t RXCheckNums = 0;
    xSPPcongSemaphore = xSemaphoreCreateBinary(); //创建SPP阻塞状态二值信号量
    xBTSearchEndSemaphore = xSemaphoreCreateBinary(); //创建蓝牙搜索状态二值信号量
    xSemaphoreGive(xSPPcongSemaphore);
    gpio_init();
    storage_init();
    qyq_uart_init();
    // /******************加密校验**************** */
    // while(CheckNums_Code != RXCheckNums)
    // {
    //     uart_write_bytes(UART_NUM_1, "AWCN", 4);//读取CH32V208校验码
    //     uart_read_bytes(UART_NUM_1, RxBuff, 4,(TickType_t)1000/portTICK_PERIOD_MS);
    //     RXCheckNums = (((uint32_t)RxBuff[0])<<24)+(((uint32_t)RxBuff[1])<<16)+(((uint32_t)RxBuff[2])<<8)+RxBuff[3];
    //     printf("RXCheckNums:%x%x%x%x\n",(uint8_t)(RXCheckNums>>24),(uint8_t)(RXCheckNums>>16),
    //                (uint8_t)(RXCheckNums>>8),(uint8_t)(RXCheckNums));
    //     printf("CheckNums_Code:%x%x%x%x\n",(uint8_t)(CheckNums_Code>>24),(uint8_t)(CheckNums_Code>>16),
    //                 (uint8_t)(CheckNums_Code>>8),(uint8_t)(CheckNums_Code));
    // }
    // /*****************校验结束***************** */
    classicBT_Init();
    uart_data_task_create();
    xTaskCreate(BT_connect_state_task, "Task1", 4096, NULL, 8, NULL);//创建蓝牙重连监测任务
}
